using System;
using System.Collections.Generic;
using System.Text;
using org.ngwt.user.server.rpc.impl;
using org.ngwt.user.client.rpc;
using System.Reflection;
using System.Security;

namespace org.ngwt.user.server.rpc
{

    /**
     * Utility class for integrating with the RPC system. This class exposes methods
     * for decoding of RPC requests, encoding of RPC responses, and invocation of
     * RPC calls on service objects. The operations exposed by this class can be
     * reused by framework implementors such as Spring and G4jsf to support a wide
     * range of service invocation policies.
     * 
     * <h3>Canonical Example</h3>
     * The following example demonstrates the canonical way to use this class.
     * 
     * {@example com.google.gwt.examples.rpc.server.CanonicalExample#processCall(String)}
     * 
     * <h3>Advanced Example</h3>
     * The following example shows a more advanced way of using this class to create
     * an adapter between GWT RPC entities and POJOs.
     * 
     * {@example com.google.gwt.examples.rpc.server.AdvancedExample#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
     */
    public static class RPC
    {
        /**
         * Maps primitive wrapper classes to their corresponding primitive class.
         */
        //private static Dictionary<Type, Type> PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS = new Dictionary<Type, Type>();

        /**
         * Static map of classes to sets of interfaces (e.g. classes). Optimizes
         * lookup of interfaces for security.
         */
        private static Dictionary<Type, Dictionary<String, bool>> serviceToImplementedInterfacesMap 
            = new Dictionary<Type, Dictionary<string, bool>>();

        private static Dictionary<String, Type> TYPE_NAMES;

        static RPC()
        {
            //PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS.Add(typeof(Boolean), Boolean.TYPE);
            //PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS.Add(typeof(Byte), Byte.TYPE);
            //PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS.Add(typeof(Character),Character.TYPE);
            //PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS.Add(typeof(Double), Double.TYPE);
            //PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS.Add(typeof(Float), Float.TYPE);
            //PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS.Add(typeof(Integer), Integer.TYPE);
            //PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS.Add(typeof(Long), Long.TYPE);
            //PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS.Add(typeof(Short), Short.TYPE);

            TYPE_NAMES = new Dictionary<String, Type>();
            TYPE_NAMES.Add("Z", typeof(bool));
            TYPE_NAMES.Add("B", typeof(byte));
            TYPE_NAMES.Add("C", typeof(char));
            TYPE_NAMES.Add("D", typeof(double));
            TYPE_NAMES.Add("F", typeof(float));
            TYPE_NAMES.Add("I", typeof(int));
            TYPE_NAMES.Add("J", typeof(long));
            TYPE_NAMES.Add("S", typeof(short));
            TYPE_NAMES.Add("java.lang.String", typeof(string));

            TYPE_NAMES.Add("[Z", typeof(bool[]));
            TYPE_NAMES.Add("[B", typeof(byte[]));
            TYPE_NAMES.Add("[C", typeof(char[]));
            TYPE_NAMES.Add("[D", typeof(double[]));
            TYPE_NAMES.Add("[F", typeof(float[]));
            TYPE_NAMES.Add("[I", typeof(int[]));
            TYPE_NAMES.Add("[J", typeof(long[]));
            TYPE_NAMES.Add("[S", typeof(short[]));
        }

        /**
         * Returns an {@link RPCRequest} that is built by decoding the contents of an
         * encoded RPC request.
         * 
         * <p>
         * This method is equivalent to calling {@link #decodeRequest(String, Class)}
         * with <code>null</code> for the type parameter.
         * </p>
         * 
         * @param encodedRequest a string that encodes the {@link RemoteService}
         *          interface, the service method to call, and the arguments to for
         *          the service method
         * @return an {@link RPCRequest} instance
         * 
         * @throws IncompatibleRemoteServiceException if any of the following
         *           conditions apply:
         *           <ul>
         *           <li>if the types in the encoded request cannot be deserialized</li>
         *           <li>if the {@link ClassLoader} acquired from
         *           <code>Thread.currentThread().getContextClassLoader()</code>
         *           cannot load the service interface or any of the types specified
         *           in the encodedRequest</li>
         *           <li>the requested interface is not assignable to
         *           {@link RemoteService}</li>
         *           <li>the service method requested in the encodedRequest is not a
         *           member of the requested service interface</li>
         *           <li>the type parameter is not <code>null</code> and is not
         *           assignable to the requested {@link RemoteService} interface
         *           </ul>
         */
        public static RPCRequest decodeRequest(String encodedRequest)
        {
            return decodeRequest(encodedRequest, null);
        }
        
        /**
         * Returns an {@link RPCRequest} that is built by decoding the contents of an
         * encoded RPC request and optionally validating that type can handle the
         * request. If the type parameter is not <code>null</code>, the
         * implementation checks that the type is assignable to the
         * {@link RemoteService} interface requested in the encoded request string.
         * 
         * <p>
         * Invoking this method with <code>null</code> for the type parameter,
         * <code>decodeRequest(encodedRequest, null)</code>, is equivalent to
         * calling <code>decodeRequest(encodedRequest)</code>.
         * </p>
         * 
         * @param encodedRequest a string that encodes the {@link RemoteService}
         *          interface, the service method, and the arguments to pass to the
         *          service method
         * @param type if not <code>null</code>, the implementation checks that the
         *          type is assignable to the {@link RemoteService} interface encoded
         *          in the encoded request string.
         * @return an {@link RPCRequest} instance
         * 
         * @throws NullPointerException if the encodedRequest is <code>null</code>
         * @throws IllegalArgumentException if the encodedRequest is an empty string
         * @throws IncompatibleRemoteServiceException if any of the following
         *           conditions apply:
         *           <ul>
         *           <li>if the types in the encoded request cannot be deserialized</li>
         *           <li>if the {@link ClassLoader} acquired from
         *           <code>Thread.currentThread().getContextClassLoader()</code>
         *           cannot load the service interface or any of the types specified
         *           in the encodedRequest</li>
         *           <li>the requested interface is not assignable to
         *           {@link RemoteService}</li>
         *           <li>the service method requested in the encodedRequest is not a
         *           member of the requested service interface</li>
         *           <li>the type parameter is not <code>null</code> and is not
         *           assignable to the requested {@link RemoteService} interface
         *           </ul>
         */
        public static RPCRequest decodeRequest(String encodedRequest, Type type) {
          return decodeRequest(encodedRequest, type, null);
        }

        /**
         * Returns an {@link RPCRequest} that is built by decoding the contents of an
         * encoded RPC request and optionally validating that type can handle the
         * request. If the type parameter is not <code>null</code>, the
         * implementation checks that the type is assignable to the
         * {@link RemoteService} interface requested in the encoded request string.
         * 
         * <p>
         * If the serializationPolicyProvider parameter is not <code>null</code>,
         * it is asked for a {@link SerializationPolicy} to use to restrict the set of
         * types that can be decoded from the request. If this parameter is
         * <code>null</code>, then only subtypes of
         * {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
         * types which have custom field serializers can be decoded.
         * </p>
         * 
         * <p>
         * Invoking this method with <code>null</code> for the type parameter,
         * <code>decodeRequest(encodedRequest, null)</code>, is equivalent to
         * calling <code>decodeRequest(encodedRequest)</code>.
         * </p>
         * 
         * @param encodedRequest a string that encodes the {@link RemoteService}
         *          interface, the service method, and the arguments to pass to the
         *          service method
         * @param type if not <code>null</code>, the implementation checks that the
         *          type is assignable to the {@link RemoteService} interface encoded
         *          in the encoded request string.
         * @param serializationPolicyProvider if not <code>null</code>, the
         *          implementation asks this provider for a
         *          {@link SerializationPolicy} which will be used to restrict the set
         *          of types that can be decoded from this request
         * @return an {@link RPCRequest} instance
         * 
         * @throws NullPointerException if the encodedRequest is <code>null</code>
         * @throws IllegalArgumentException if the encodedRequest is an empty string
         * @throws IncompatibleRemoteServiceException if any of the following
         *           conditions apply:
         *           <ul>
         *           <li>if the types in the encoded request cannot be deserialized</li>
         *           <li>if the {@link ClassLoader} acquired from
         *           <code>Thread.currentThread().getContextClassLoader()</code>
         *           cannot load the service interface or any of the types specified
         *           in the encodedRequest</li>
         *           <li>the requested interface is not assignable to
         *           {@link RemoteService}</li>
         *           <li>the service method requested in the encodedRequest is not a
         *           member of the requested service interface</li>
         *           <li>the type parameter is not <code>null</code> and is not
         *           assignable to the requested {@link RemoteService} interface
         *           </ul>
         */
        public static RPCRequest decodeRequest(String encodedRequest, Type type,
            SerializationPolicyProvider serializationPolicyProvider) {
          if (encodedRequest == null) {
            throw new NullReferenceException("encodedRequest cannot be null");
          }

          if (encodedRequest.Length == 0) {
            throw new ArgumentException("encodedRequest cannot be empty");
          }

          //ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

          try {
            ServerSerializationStreamReader streamReader 
                = new ServerSerializationStreamReader(serializationPolicyProvider);
            streamReader.prepareToRead(encodedRequest);

            // Read the name of the RemoteService interface
            String serviceIntfName = streamReader.readString();
            
            if (type != null) {
              if (!implementsInterface(type, serviceIntfName)) {
                // The service does not implement the requested interface
                throw new IncompatibleRemoteServiceException(
                    "Blocked attempt to access interface '" + serviceIntfName
                        + "', which is not implemented by '" + printTypeName(type)
                        + "'; this is either misconfiguration or a hack attempt");
              }
            }
            
            SerializationPolicy serializationPolicy = streamReader.getSerializationPolicy();
            Type serviceIntf;
            try {
              serviceIntf = getClassFromSerializedName(serviceIntfName);
              if (!typeof(RemoteService).IsAssignableFrom(serviceIntf)) {
                // The requested interface is not a RemoteService interface
                throw new IncompatibleRemoteServiceException(
                    "Blocked attempt to access interface '"
                        + printTypeName(serviceIntf)
                        + "', which doesn't extend RemoteService; this is either misconfiguration or a hack attempt");
              }
            } catch (Exception e) {
              throw new IncompatibleRemoteServiceException(
                  "Could not locate requested interface '" + serviceIntfName
                      + "' in default classloader", e);
            }
            

            String serviceMethodName = streamReader.readString();

            int paramCount = streamReader.readInt();
            Type[] parameterTypes = new Type[paramCount];

            for (int i = 0; i < parameterTypes.Length; i++) {
              String paramClassName = streamReader.readString();
              try {
                parameterTypes[i] = getClassFromSerializedName(paramClassName);
              } catch (Exception e) {
                throw new IncompatibleRemoteServiceException("Parameter " + i
                    + " of is of an unknown type '" + paramClassName + "'", e);
              }
            }
            
            try {
              MethodInfo method = serviceIntf.GetMethod(serviceMethodName, parameterTypes);

              Object[] parameterValues = new Object[parameterTypes.Length];
              for (int i = 0; i < parameterValues.Length; i++) {
                parameterValues[i] = streamReader.deserializeValue(parameterTypes[i]);
              }

              return new RPCRequest(method, parameterValues, serializationPolicy);

            } catch (Exception ) {
              throw new IncompatibleRemoteServiceException(
                  formatMethodNotFoundErrorMessage(serviceIntf, serviceMethodName,
                      parameterTypes));
            }
          } catch (SerializationException ex) {
            throw new IncompatibleRemoteServiceException(ex.Message, ex);
          }
        }


        /**
         * Returns a string that encodes an exception. If method is not
         * <code>null</code>, it is an error if the exception is not in the
         * method's list of checked exceptions.
         * 
         * @param serviceMethod the method that threw the exception, may be
         *          <code>null</code>
         * @param cause the {@link Throwable} that was thrown
         * @return a string that encodes the exception
         * 
         * @throws NullPointerException if the the cause is <code>null</code>
         * @throws SerializationException if the result cannot be serialized
         * @throws UnexpectedException if the result was an unexpected exception (a
         *           checked exception not declared in the serviceMethod's signature)
         */
        public static String encodeResponseForFailure(MethodInfo serviceMethod,Exception cause)
        {
          return encodeResponseForFailure(serviceMethod, cause,getDefaultSerializationPolicy());
        }


        /**
         * Returns a string that encodes an exception. If method is not
         * <code>null</code>, it is an error if the exception is not in the
         * method's list of checked exceptions.
         * 
         * <p>
         * If the serializationPolicy parameter is not <code>null</code>, it is
         * used to determine what types can be encoded as part of this response. If
         * this parameter is <code>null</code>, then only subtypes of
         * {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
         * types which have custom field serializers may be encoded.
         * </p>
         * 
         * @param serviceMethod the method that threw the exception, may be
         *          <code>null</code>
         * @param cause the {@link Throwable} that was thrown
         * @param serializationPolicy determines the serialization policy to be used
         * @return a string that encodes the exception
         * 
         * @throws NullPointerException if the the cause or the serializationPolicy
         *           are <code>null</code>
         * @throws SerializationException if the result cannot be serialized
         * @throws UnexpectedException if the result was an unexpected exception (a
         *           checked exception not declared in the serviceMethod's signature)
         */
        public static String encodeResponseForFailure(MethodInfo serviceMethod,
            Exception cause, SerializationPolicy serializationPolicy)
        {
          if (cause == null) {
            throw new NullReferenceException("cause cannot be null");
          }

          if (serializationPolicy == null) {
              throw new NullReferenceException("serializationPolicy");
          }

          //if (serviceMethod != null && !RPC.isExpectedException(serviceMethod, cause)) {
          //  throw new UnexpectedException("Service method '"
          //      + getSourceRepresentation(serviceMethod)
          //      + "' threw an unexpected exception: " + cause.ToString(), cause);
          //}

          return encodeResponse(cause.GetType(), cause, true, serializationPolicy);
        }


        /**
         * Returns a string that encodes the object. It is an error to try to encode
         * an object that is not assignable to the service method's return type.
         * 
         * @param serviceMethod the method whose result we are encoding
         * @param object the instance that we wish to encode
         * @return a string that encodes the object, if the object is compatible with
         *         the service method's declared return type
         * 
         * @throws IllegalArgumentException if the result is not assignable to the
         *           service method's return type
         * @throws NullPointerException if the service method is <code>null</code>
         * @throws SerializationException if the result cannot be serialized
         */
        public static String encodeResponseForSuccess(MethodInfo serviceMethod, Object obj)
        {
            return encodeResponseForSuccess(serviceMethod, obj, getDefaultSerializationPolicy());
        }

        /**
         * Returns a string that encodes the object. It is an error to try to encode
         * an object that is not assignable to the service method's return type.
         * 
         * <p>
         * If the serializationPolicy parameter is not <code>null</code>, it is
         * used to determine what types can be encoded as part of this response. If
         * this parameter is <code>null</code>, then only subtypes of
         * {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
         * types which have custom field serializers may be encoded.
         * </p>
         * 
         * @param serviceMethod the method whose result we are encoding
         * @param object the instance that we wish to encode
         * @param serializationPolicy determines the serialization policy to be used
         * @return a string that encodes the object, if the object is compatible with
         *         the service method's declared return type
         * 
         * @throws IllegalArgumentException if the result is not assignable to the
         *           service method's return type
         * @throws NullPointerException if the serviceMethod or the
         *           serializationPolicy are <code>null</code>
         * @throws SerializationException if the result cannot be serialized
         */
        public static String encodeResponseForSuccess(MethodInfo serviceMethod,
            Object obj, SerializationPolicy serializationPolicy)
        {
          if (serviceMethod == null) {
            throw new NullReferenceException("serviceMethod cannot be null");
          }

          if (serializationPolicy == null) {
            throw new NullReferenceException("serializationPolicy");
          }

          Type methodReturnType = serviceMethod.ReturnType;
          if (methodReturnType != typeof(void) && obj != null) {
            Type actualReturnType;
            if (methodReturnType.IsPrimitive) {
              actualReturnType = getPrimitiveClassFromWrapper(obj.GetType());
            } else {
              actualReturnType = obj.GetType();
            }

            if (actualReturnType == null
                || !methodReturnType.IsAssignableFrom(actualReturnType)) {
              throw new ArgumentException("Type '"
                  + printTypeName(obj.GetType())
                  + "' does not match the return type in the method's signature: '"
                  + getSourceRepresentation(serviceMethod) + "'");
            }
          }

          return encodeResponse(methodReturnType, obj, false, serializationPolicy);
        }

        /**
         * Returns a default serialization policy.
         * 
         * @return the default serialization policy.
         */
        public static SerializationPolicy getDefaultSerializationPolicy()
        {
            //return LegacySerializationPolicy.getInstance();
            return null;
        }

        /**
         * Returns a string that encodes the result of calling a service method, which
         * could be the value returned by the method or an exception thrown by it.
         * 
         * <p>
         * This method does no security checking; security checking must be done on
         * the method prior to this invocation.
         * </p>
         * 
         * @param target instance on which to invoke the serviceMethod
         * @param serviceMethod the method to invoke
         * @param args arguments used for the method invocation
         * @return a string which encodes either the method's return or a checked
         *         exception thrown by the method
         * 
         * @throws SecurityException if the method cannot be accessed or if the number
         *           or type of actual and formal arguments differ
         * @throws SerializationException if an object could not be serialized by the
         *           stream
         * @throws UnexpectedException if the serviceMethod throws a checked exception
         *           that is not declared in its signature
         */
        public static String invokeAndEncodeResponse(Object target,
            MethodInfo serviceMethod, Object[] args) 
        {
          return invokeAndEncodeResponse(target, serviceMethod, args,
              getDefaultSerializationPolicy());
        }

        /**
         * Returns a string that encodes the result of calling a service method, which
         * could be the value returned by the method or an exception thrown by it.
         * 
         * <p>
         * If the serializationPolicy parameter is not <code>null</code>, it is
         * used to determine what types can be encoded as part of this response. If
         * this parameter is <code>null</code>, then only subtypes of
         * {@link com.google.gwt.user.client.rpc.IsSerializable IsSerializable} or
         * types which have custom field serializers may be encoded.
         * </p>
         * 
         * <p>
         * This method does no security checking; security checking must be done on
         * the method prior to this invocation.
         * </p>
         * 
         * @param target instance on which to invoke the serviceMethod
         * @param serviceMethod the method to invoke
         * @param args arguments used for the method invocation
         * @param serializationPolicy determines the serialization policy to be used
         * @return a string which encodes either the method's return or a checked
         *         exception thrown by the method
         * 
         * @throws NullPointerException if the serviceMethod or the
         *           serializationPolicy are <code>null</code>
         * @throws SecurityException if the method cannot be accessed or if the number
         *           or type of actual and formal arguments differ
         * @throws SerializationException if an object could not be serialized by the
         *           stream
         * @throws UnexpectedException if the serviceMethod throws a checked exception
         *           that is not declared in its signature
         */
        public static String invokeAndEncodeResponse(Object target,
            MethodInfo serviceMethod, Object[] args,
            SerializationPolicy serializationPolicy) 
        {
          if (serviceMethod == null) {
              throw new NullReferenceException("serviceMethod");
          }

          if (serializationPolicy == null) {
              throw new NullReferenceException("serializationPolicy");
          }

          String responsePayload;
          try 
          {
            Object result = serviceMethod.Invoke(target, args);

            responsePayload = encodeResponseForSuccess(serviceMethod, result,
                serializationPolicy);
          }
          catch (MethodAccessException e)
          {
            SecurityException securityException = new SecurityException(
                formatIllegalAccessErrorMessage(target, serviceMethod),e);
            //securityException.InitCause(e);
            throw securityException;
          }
          catch (ArgumentException e) 
          {
            SecurityException securityException = new SecurityException(
                formatIllegalArgumentErrorMessage(target, serviceMethod, args),e);
            //securityException.initCause(e);
            throw securityException;
        }
        catch (TargetInvocationException e)
        {
            // Try to encode the caught exception
            //
            Exception cause = e.InnerException;

            responsePayload = encodeResponseForFailure(serviceMethod, cause,
                serializationPolicy);
          }

          return responsePayload;
        }

        /**
         * Returns a string that encodes the results of an RPC call. Private overload
         * that takes a flag signaling the preamble of the response payload.
         * 
         * @param object the object that we wish to send back to the client
         * @param wasThrown if true, the object being returned was an exception thrown
         *          by the service method; if false, it was the result of the service
         *          method's invocation
         * @return a string that encodes the response from a service method
         * @throws SerializationException if the object cannot be serialized
         */
        private static String encodeResponse(Type responseClass, Object obj,
            bool wasThrown, SerializationPolicy serializationPolicy)
        {

          ServerSerializationStreamWriter stream = new ServerSerializationStreamWriter(serializationPolicy);

          stream.prepareToWrite();
          if (responseClass != typeof(void)) {
            stream.serializeValue(obj, responseClass);
          }

          String bufferStr = (wasThrown ? "//EX" : "//OK") + stream.toString();
          return bufferStr;
        }


        private static String formatIllegalAccessErrorMessage(Object target,
            MethodInfo serviceMethod)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Blocked attempt to access inaccessible method '");
            sb.Append(getSourceRepresentation(serviceMethod));
            sb.Append("'");

            if (target != null)
            {
                sb.Append(" on target '");
                sb.Append(printTypeName(target.GetType()));
                sb.Append("'");
            }

            sb.Append("; this is either misconfiguration or a hack attempt");

            return sb.ToString();
        }

        private static String formatIllegalArgumentErrorMessage(Object target,
            MethodInfo serviceMethod, Object[] args)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Blocked attempt to invoke method '");
            sb.Append(getSourceRepresentation(serviceMethod));
            sb.Append("'");

            if (target != null)
            {
                sb.Append(" on target '");
                sb.Append(printTypeName(target.GetType()));
                sb.Append("'");
            }

            sb.Append(" with invalid arguments");

            if (args != null && args.Length > 0)
            {
                foreach(object param in args)
                {
                    sb.Append(param.ToString());
                }
            }

            return sb.ToString();
        }

        private static String formatMethodNotFoundErrorMessage(Type serviceIntf,
            String serviceMethodName, Type[] parameterTypes) {
                StringBuilder sb = new StringBuilder();

          sb.Append("Could not locate requested method '");
          sb.Append(serviceMethodName);
          sb.Append("(");
          for (int i = 0; i < parameterTypes.Length; ++i) {
            if (i > 0) {
              sb.Append(", ");
            }
            sb.Append(printTypeName(parameterTypes[i]));
          }
          sb.Append(")'");

          sb.Append(" in interface '");
          sb.Append(printTypeName(serviceIntf));
          sb.Append("'");

          return sb.ToString();
        }

        /**
         * Returns the {@link Class} instance for the named class or primitive type.
         * 
         * @param serializedName the serialized name of a class or primitive type
         * @param classLoader the classLoader used to load {@link Class}es
         * @return Class instance for the given type name
         * @throws ClassNotFoundException if the named type was not found
         */
        private static Type getClassFromSerializedName(String serializedName)
        {
            try
            {
                if (TYPE_NAMES.ContainsKey(serializedName))
                {
                    return TYPE_NAMES[serializedName];
                }

                return FindType(serializedName);
                //return Class.forName(serializedName, false, classLoader);

            }
            catch(Exception e)
            {
                string msg = e.Message;
                return null;
            }
        }
        public static Type FindType(string typeName)
        {
            Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
            for( int i=0;i< ass.Length;i++)
            {
                Type t = ass[i].GetType(typeName);
                if (t != null)
                    return t;
            }
            return null;
        }

        /**
         * Returns the {@link java.lang.Class Class} for a primitive type given its
         * corresponding wrapper {@link java.lang.Class Class}.
         * 
         * @param wrapperClass primitive wrapper class
         * @return primitive class
         */
        private static Type getPrimitiveClassFromWrapper(Type wrapperClass) {
          //return PRIMITIVE_WRAPPER_CLASS_TO_PRIMITIVE_CLASS.get(wrapperClass);
            return wrapperClass;
        }

        /**
         * Returns the source representation for a method signature.
         * 
         * @param method method to get the source signature for
         * @return source representation for a method signature
         */
        private static String getSourceRepresentation(MethodInfo method) {
          return method.ToString().Replace('$', '.');
        }

        /**
         * Used to determine whether the specified interface name is implemented by
         * the service class. This is done without loading the class (for security).
         */
        private static bool implementsInterface(Type service, String intfName) 
        {
          lock (serviceToImplementedInterfacesMap) {
            // See if it's cached.
            //
            Dictionary<String,bool> interfaceSet = serviceToImplementedInterfacesMap.ContainsKey(service)
                ? serviceToImplementedInterfacesMap[service] : null;
            if (interfaceSet != null) {
              if (interfaceSet.ContainsKey(intfName)) {
                return true;
              }
            } else {
              interfaceSet = new Dictionary<String,bool>();
              serviceToImplementedInterfacesMap.Add(service, interfaceSet);
            }

            if (!service.IsInterface) {
              while ((service != null) /*&& !RemoteServiceServlet.class.equals(service)*/) {
                Type[] intfs = service.GetInterfaces();
                foreach (Type intf in intfs) {
                  if (implementsInterfaceRecursive(intf, intfName)) {
                    interfaceSet.Add(intfName,true);
                    return true;
                  }
                }

                // did not find the interface in this class so we look in the
                // superclass
                //
                service = service.BaseType;
              }
            } else {
              if (implementsInterfaceRecursive(service, intfName)) {
                interfaceSet.Add(intfName,true);
                return true;
              }
            }

            return false;
          }
        }

        /**
         * Only called from implementsInterface().
         */
        private static bool implementsInterfaceRecursive(Type clazz,
            String intfName) {
          //assert (clazz.IsInterface);

          if (clazz.FullName.Equals(intfName)) {
            return true;
          }

          // search implemented interfaces
          Type[] intfs = clazz.GetInterfaces();
          foreach (Type intf in intfs) {
            if (implementsInterfaceRecursive(intf, intfName)) {
              return true;
            }
          }

          return false;
        }

        /**
         * Straight copy from
         * {@link com.google.gwt.dev.util.TypeInfo#getSourceRepresentation(Class)} to
         * avoid runtime dependency on gwt-dev.
         */
        private static String printTypeName(Type type) {
          // Primitives
          //
          if (type.Equals(typeof(int))) {
            return "int";
          } else if (type.Equals(typeof(long))) {
            return "long";
          } else if (type.Equals(typeof(short))) {
            return "short";
          } else if (type.Equals(typeof(byte))) {
            return "byte";
          } else if (type.Equals(typeof(char))) {
            return "char";
          } else if (type.Equals(typeof(bool))) {
            return "boolean";
          } else if (type.Equals(typeof(float))) {
            return "float";
          } else if (type.Equals(typeof(double))) {
            return "double";
          }

          // Arrays
          //
          if (type.IsArray) {
            Type componentType = type.GetElementType();
            return printTypeName(componentType) + "[]";
          }

          // Everything else
          //
          return type.Name.Replace('$', '.');
        }
    }
}
